package com.dxy.netty.heartbeatcheck;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler;
import io.netty.handler.timeout.IdleStateHandler;

import java.util.concurrent.TimeUnit;

/**
 * @Description netty心跳检测服务器
 * netty心跳检测机制介绍：
 * 1、https://www.cnblogs.com/rickiyang/p/12792120.html
 * 2、https://www.pudn.com/news/6286fd8116e0ca7141d234ab.html
 * @Author dangxianyue
 * @Date 2023/1/6 11:49
 */
public class NettyHeartbeatCheckServer {

    private final int port;

    public NettyHeartbeatCheckServer(int port) {
        this.port = port;
    }

    public static void main(String[] args) {
        try {
            new NettyHeartbeatCheckServer(8089).run();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    public void run() throws InterruptedException {
        // 创建线程池执行器
        EventLoopGroup bossGroup = new NioEventLoopGroup(1);
        EventLoopGroup workerGroup = new NioEventLoopGroup(8);
        try {
            // 服务器启动引导对象
            ServerBootstrap serverBootstrap = new ServerBootstrap();
            serverBootstrap.group(bossGroup, workerGroup)
                    .channel(NioServerSocketChannel.class)
                    .option(ChannelOption.SO_BACKLOG, 128)
                    .option(ChannelOption.SO_KEEPALIVE, true)
                    .handler(new LoggingHandler(LogLevel.INFO)) // 为 bossGroup 添加 日志处理器
                    .childHandler(new ChannelInitializer<SocketChannel>() {
                        @Override
                        protected void initChannel(SocketChannel socketChannel) throws Exception {
                            // 添加处理器
                            ChannelPipeline pipeline = socketChannel.pipeline();
                            // 1. 添加空闲状态处理器 ：
                            // readerIdleTime: 表示多长时间没有读入io事件，就会发送一个心跳检测包，检测是否连接状态，为0则不检测
                            // writerIdleTime: 表示多长时间没有写出io事件，就会发送一个心跳检测包，检测是否连接状态，为0则不检测
                            // allIdleTime：   表示多长时间没有读入和写出io事件，就会发送一个心跳检测包，检测是否连接状态，为0则不检测
                            //  2. 文档说明
                            // Triggers an {@link IdleStateEvent } when a {@link Channel} has not performed
                            //     * read, write, or both operation for a while.
                            // 3. 当 IdleStateEvent 事件触发后， 就会传递给管道的 下一个处理器 去处理
                            // 通过调用下一个handler的 userEventTriggered 方法，即在该方法中处理IdleStateEvent 事件；
                            pipeline.addLast(new IdleStateHandler(4, 5, 7, TimeUnit.SECONDS));
                            // 添加一个对空闲检测 进一步处理的handler（自定义 ）
                            pipeline.addLast(new NettyHeartbeatCheckServerHandler());
                        }
                    });
            // 启动服务器，监听端口，阻塞直到启动成功
            ChannelFuture channelFuture = serverBootstrap.bind(this.port).sync();
            // 阻塞直到channel关闭
            channelFuture.channel().closeFuture().sync();
        } finally {
            bossGroup.shutdownGracefully().sync();
            workerGroup.shutdownGracefully().sync();
        }
    }
}
